package org.ccay.async.conduit;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.ccay.async.AsyncMessage;
import org.ccay.async.config.AsyncConduitConfig;
import org.ccay.async.impl.AsyncFramework;
import org.ccay.core.ioc.Ccay;
import org.ccay.core.ioc.CcayBeansException;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogger;

/**
 * 默认的通道选择器，依赖AsyncFramework来根据消息获取配置的通道。
 */
public class DefaultConduitSelector implements ConduitSelector {
	
	/**
	 * 日志记录器
	 */
	private ILogger logger = CcayLoggerFactory.getLogger(DefaultConduitSelector.class);

	/* (non-Javadoc)
	 * @see org.ccay.core.async.ConduitSelector#select(org.ccay.core.async.Message)
	 */
	public List<AsyncConduit> select(AsyncMessage message) {
		// 消息对应的通道配置
		AsyncConduitConfig conduitConf = AsyncFramework.getInstance().getConduitConfig(message);
		if(conduitConf == null) {
			logger.error("Can't find async conduit configuration for message: "+message.getType());
			return null;
		}
		
		List<AsyncConduit> conduits = getRawConduits(conduitConf);
		
		// 通道定义为空时使用默认通道
		if(conduits.isEmpty()) {
			conduits.add(AsyncFramework.getInstance().getDefaultConduit());
		}
		
		// 将通道装饰成ContextAwareConduit
		if(!conduitConf.isContextAware()) {
			return conduits;
		} else {
			return decorateConduits(conduits);
		}
	}
	
	/**
	 * 获取配置的通道列表。
	 * 
	 * @param conduitConf
	 * @return
	 */
	private List<AsyncConduit> getRawConduits(AsyncConduitConfig conduitConf) {
		List<AsyncConduit> rawConduits = new ArrayList<AsyncConduit>(1);
		
		// 通道对应的Bean ID列表
		List<String> conduits = conduitConf.getConduits();
		if(conduits == null || conduits.isEmpty()) {
			return rawConduits;
		}
		
		Iterator<String> iter = conduits.iterator();
		while(iter.hasNext()) {
			// 获取通道的定义
			AsyncConduit conduit = getNamedConduit(iter.next());
			if(conduit != null) {
				rawConduits.add(conduit);
			}
		}
		
		return rawConduits;
	}
	
	/**
	 * 将通道装饰成具有受控上下文的通道。
	 * 
	 * @param rawConduits
	 * @return
	 */
	private List<AsyncConduit> decorateConduits(List<AsyncConduit> rawConduits) {
		List<AsyncConduit> ctxAwareConduits = new ArrayList<AsyncConduit>();
		
		Iterator<AsyncConduit> iter = rawConduits.iterator();
		while(iter.hasNext()) {
			ctxAwareConduits.add(new ContextAwareConduit(iter.next()));
		}
		
		return ctxAwareConduits;
	}
	
	/**
	 * 获取指定名称的通道定义。
	 * 
	 * @param conduitName
	 * @return
	 */
	private AsyncConduit getNamedConduit(String conduitName) {
		try {
			return Ccay.getContext().getBean(conduitName, AsyncConduit.class);
		} catch (CcayBeansException ex) {
			logger.warn("Can't find async conduit definition: "+conduitName);
			return null;
		}
	}

}
